/*
 * Copyright © OpenAtom Foundation.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *      http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package io.iec.edp.caf.msu.client.register;

import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import io.iec.edp.caf.commons.exception.CAFRuntimeException;
import io.iec.edp.caf.commons.exception.entity.DefaultExceptionProperties;
import io.iec.edp.caf.commons.exception.entity.ExceptionErrorCode;
import io.iec.edp.caf.commons.exception.ExceptionLevel;
import io.iec.edp.caf.commons.runtime.CafEnvironment;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.msu.api.ServiceUnitAwareService;
import io.iec.edp.caf.msu.api.client.ServiceRegistry;
import io.iec.edp.caf.msu.api.client.ServiceUnitInfoRegistry;
import io.iec.edp.caf.msu.api.entity.MsuProperties;
import io.iec.edp.caf.msu.api.entity.ServiceUnitInfo;
import io.iec.edp.caf.msu.api.entity.ServiceUnitRegisterInfo;
import io.iec.edp.caf.msu.api.server.MsuServiceRegistry;
import io.iec.edp.caf.tenancy.api.context.MultiTenantContextInfo;
import io.iec.edp.caf.tenancy.core.context.MultiTenantContextHolder;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.context.annotation.DependsOn;


import javax.annotation.PreDestroy;
import javax.swing.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * 基于Nacos的服务注册
 * @author Leon Huo
 */
@Slf4j
public class NacosRegisterImpl implements ServiceRegistry {
    private NamingService namingService;
    private MsuProperties configuration;
    private ServiceUnitInfoRegistry msuServiceRegistry= SpringBeanUtils.getBean(ServiceUnitInfoRegistry.class);

    public NacosRegisterImpl(NamingService namingService, MsuProperties configuration) {
        this.namingService = namingService;
        this.configuration = configuration;
    }

    /**
     * 应用注册
     *
     * @param serviceUnitRegisterInfo
     * @return
     */
    @Override
    public Boolean register(ServiceUnitRegisterInfo serviceUnitRegisterInfo) {
        registerIntoNacos(serviceUnitRegisterInfo.getServiceUnitNameList());
//        registerIntoNacosAndDb(serviceUnitRegisterInfo);
        msuServiceRegistry.registerServiceUnitInfos(serviceUnitRegisterInfo);
        return true;
    }

    @Override
    @PreDestroy
    public Boolean unRegister() {
        log.info("nacos register start unregist su");
        var srv = SpringBeanUtils.getBean(ServiceUnitAwareService.class);
        List<String> suInfoList = srv.getEnabledServiceUnits();
        ServiceUnitRegisterInfo serviceUnitRegisterInfo = srv.getServiceUnitRegisterInfo(configuration.getApplicationName(),configuration.getServiceName(),suInfoList);

        unRegisterIntoNacos(serviceUnitRegisterInfo.getServiceUnitNameList());
        msuServiceRegistry.unRegisterServiceUnitInfos(serviceUnitRegisterInfo);
//        unRegisterIntoNacosAndDb(serviceUnitRegisterInfo);
        log.info("nacos register end unregist su");
        return true;
    }

    private void registerIntoNacos(List<ServiceUnitInfo> suList){
        //当前要求lcm,msu的su先注册，然后是ebs的，再是其他的
        try {
            var ip = CafEnvironment.getLocalIp(configuration.getIp().getPrefix());
            var port = CafEnvironment.getPort();
            suList.forEach(x->{
                try {
                    namingService.registerInstance(x.getName().toLowerCase(), ip, port);
                } catch (NacosException e) {
                    log.error("注册su:"+x+"到nacos异常："+e.getMessage(),e);
                }
            });
        } catch (Throwable e) {
            throw new RuntimeException("注册su到nacos失败："+e.getMessage(),e);
//            throw new CAFRuntimeException(DefaultExceptionProperties.SERVICE_UNIT,
//                    DefaultExceptionProperties.RESOURCE_FILE,
//                    ExceptionErrorCode.nacosError,
//                    new String[]{},
//                    e, ExceptionLevel.Error, false);
        }
    }

    @Deprecated
    private void registerIntoNacosAndDb(ServiceUnitRegisterInfo serviceUnitRegisterInfo){
        //这里先注册的nacos再注册的数据库，所以MicroServiceUnit直接注册进去了，后面往数据库注册时，去发现这个MicroServiceUnit是有的
        try {
            namingService.registerInstance(configuration.getServiceName(), CafEnvironment.getLocalIp(configuration.getIp().getPrefix()), CafEnvironment.getPort());
        } catch (NacosException e) {
            throw new CAFRuntimeException(DefaultExceptionProperties.SERVICE_UNIT,
                    DefaultExceptionProperties.RESOURCE_FILE,
                    ExceptionErrorCode.nacosError,
                    new String[]{},
                    e, ExceptionLevel.Error, false);
        }

        MsuServiceRegistry msuServiceRegistry = SpringBeanUtils.getBean(MsuServiceRegistry.class);
        Boolean msuRegister = msuServiceRegistry.register(serviceUnitRegisterInfo);

        if (!msuRegister) {
            throw new CAFRuntimeException(DefaultExceptionProperties.SERVICE_UNIT,
                    DefaultExceptionProperties.RESOURCE_FILE,
                    ExceptionErrorCode.serviceRegisterError,
                    new String[]{},
                    null, ExceptionLevel.Error, false);
        }

    }

    private void unRegisterIntoNacos(List<ServiceUnitInfo> suList){
        //当前要求lcm,msu的su先注册，然后是ebs的，再是其他的
        try {
            var ip = CafEnvironment.getLocalIp(configuration.getIp().getPrefix());
            var port = CafEnvironment.getPort();
            suList.forEach(x->{
                try {
                    namingService.deregisterInstance(x.getName().toLowerCase(), ip, port);
                } catch (NacosException e) {
                    log.error("unregist su:"+x+" to nacos exception："+e.getMessage(),e);
                }
            });
        } catch (Throwable e) {
            throw new RuntimeException("unregist su to nacos exception："+e.getMessage(),e);
        }
    }

    @Deprecated
    private void unRegisterIntoNacosAndDb(ServiceUnitRegisterInfo serviceUnitRegisterInfo){
        var servcieName = configuration.getServiceName();
        var ip = CafEnvironment.getLocalIp(configuration.getIp().getPrefix());
        var port = CafEnvironment.getPort();

        try {

            try {

                namingService.deregisterInstance(configuration.getServiceName(), CafEnvironment.getLocalIp(configuration.getIp().getPrefix()), CafEnvironment.getPort());
            } catch (NacosException e) {
                throw new CAFRuntimeException("","","unregist："+configuration.getServiceName()+","+ip+","+port+"to nacos exception",e,ExceptionLevel.Error,false);
            }

            var temp = namingService.getAllInstances(servcieName);

            //当前服务只有一个实例的情况下，才能注销掉msuregisterinfo表里的信息。
            if(temp.size()==1){
                //这里销毁阶段时，rest都被销毁，rpc过去会404，先暂时强制删主库数据吧
//                LinkedHashMap<String, Object> paramMap = new LinkedHashMap();
//                paramMap.put("info", serviceUnitRegisterInfo);
//                Boolean msuRegister = this.msuServerInvoker.remoteInvoke(Boolean.class, "io.iec.edp.caf.msu.api.server.MsuServiceRegistry.unRegister", paramMap);
//                if (!msuRegister) {
//                    throw new CAFRuntimeException("","","注销："+configuration.getServiceName()+","+ip+","+port+"到gspmsuregisterinfp失败",null,ExceptionLevel.Error,false);
//                }
                try{
                    //直接注册到主库
                    MultiTenantContextInfo contextInfo = new MultiTenantContextInfo();
                    contextInfo.setMasterDb(true);
                    MultiTenantContextHolder.set(contextInfo);
                    MsuServiceRegistry msu = SpringBeanUtils.getBean(MsuServiceRegistry.class);
                    msu.unRegister(serviceUnitRegisterInfo);
                }finally {
                    MultiTenantContextHolder.set(null);
                }

            }

        } catch (NacosException e) {
            log.error(e.getErrMsg(),e);
        }

    }
}
